<template>
  <div class="center-wrapper">
    <!-- 地铁线路 -->
    <div id="subLine-controller">
      <div class="title-bg"><i class="iconfont icon-luxuan"></i> 地铁线路</div>
      <div class="item-wrapper">
        <div
          class="item"
          v-for="(item, index) in subLineData"
          :key="index"
          @click.stop="handleSublineClick(item, index)"
        >
          <div
            class="box"
            :style="{
              borderColor: item.color,
              backgroundColor: item.choosed ? item.color : '',
            }"
          ></div>
          <span :style="{ color: '#34c5cf' }">{{ item.name.slice(-3) }}</span>
        </div>
      </div>
    </div>
    <!-- 站点列表 -->
    <div id="station-controller">
      <div class="title-bg"><i class="iconfont icon-metro"></i> 地铁站点</div>
      <div class="item-wrapper">
        <div
          class="item"
          :key="index"
          v-for="(item, index) in stationData"
          :data-fulltext="item.name"
        >
          <div
            class="box"
            :style="{
              backgroundColor:
                index - 1 < metroIndex ? '#fff' : 'rgba(0,0,0,0)',
            }"
          ></div>
          <span :style="{ color: '#34c5cf' }">{{ item.name }}</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { getLine } from '@/api/line.js';
import { useLineData } from '@/store/index.js';

import { getSiteTimes } from '@/api/core.js';
import SimpleLabel from '@/cesiumTools/Bubble/htmlMarker.js';

const lineData = useLineData();
const viewer = lineData.Viewer;

// 定义地铁线路数据
const subLineData = ref([]);
const currentLine = ref('');

// 定义站点数据
const stationData = ref([]);
const metroIndex = ref(0);

let clockListener;
let trainEntity;
// 地铁线路切换
const handleSublineClick = async (item, index) => {
  // 如果点击的是同一个站线，返回
  if (currentLine.value?.name == item.name) return;

  // removeCurrentRoute()
  if (trainEntity) {
    viewer.entities.remove(trainEntity);
    trainEntity = null;
  }
  if (popupController) {
    popupController.removeMarker()
    popupController = null
  }

  // 存储当前选中的地铁线路
  currentLine.value = item;

  // 点击站线，更新数据，渲染轨道列车，视角跳转，渲染popup
  const { stationsList, id } = item;

  // 控制ui
  subLineData.value.forEach(item => {
    if (item.id == id) {
      item.choosed = true;
    } else {
      item.choosed = false;
    }
  });

  // 根据地铁线路的索引获取地铁站点的数据
  stationData.value = stationsList;

  // 从模拟服务端获取列车信息
  const trainInfo = await getTrainDataByLineId(id);
  // 渲染轨道列车
  renderTrain(trainInfo);
  // 渲染气泡框
  renderBubble(trainInfo);
};

onMounted(async () => {
  // 请求地铁线路数据
  const data = await getLine();

  // 地铁线路数据
  subLineData.value = data.map(item => {
    // 生成三个0到255之间的随机整数，分别代表RGB值
    let r = Math.floor(Math.random() * 256);
    let g = Math.floor(Math.random() * 256);
    let b = Math.floor(Math.random() * 256);
    return { ...item, choosed: false, color: `rgb(${r}, ${g}, ${b})` };
  });
});

onBeforeUnmount(() => {
  if (trainEntity) {
    viewer.entities.remove(trainEntity);
    trainEntity = null;
  }
  if (clockListener) {
    viewer.clock.onTick.removeEventListener(clockListener);
    clockListener = null;
  }
  if (popupController) {
    popupController.removeMarker()
    popupController = null
  }
});

// 假设从服务端获取到列车的实时信息
const getTrainDataByLineId = id => {
  console.log('举例一号线的id为', id);
  return new Promise((resolve, reject) => {
    // 构造一个随机的站点index
    let startIndex = 0;
    // 一号线的第一个站点
    const startStationInfo = stationData.value[startIndex];
    // 一号线的第二个站点
    const endStationInfo = stationData.value[startIndex + 1];

    console.log('当前线路的坐标为', currentLine.value.paths[2]);
    // 由于站点坐标和路径坐标可能不会完全匹配，这里只是模拟数据，给列车虚构一个坐标点
    const trainData = {
      startIndex,
      currentPassengers: Math.ceil(Math.random() * 1000), //乘客数
      startStation: startStationInfo, // 第一个站点的信息
      destination: endStationInfo, // 第二个站点的信息
      lineName: currentLine.value.name, // 当前线路的名称: 一号线
      currentSpeed: Math.ceil(Math.random() * 100 + 100), // 当前火车的速度
      currentPosition: currentLine.value.paths[2], // 当前线路的坐标
    };
    
    resolve(trainData);
  });
};

// 渲染轨道列车
const renderTrain = trainInfo => {
  // 获取出发站点，得到metroIndex
  const { startIndex, currentPosition, currentSpeed } = trainInfo;
  metroIndex.value = startIndex;

  // 索引号是2, 指的是一号线路中path下标为2的数据, 个人理解是列车的初始坐标
  const pathIndex = currentLine.value.paths.findIndex(
    path => path === currentPosition
  );
  console.log(pathIndex);

  // 三个属性: property记录每个坐标点的坐标和经过时间, startTime为线路起点时间, endTime为线路终点时间
  const { property, startTime, endTime } = handlePosition(
    currentSpeed,
    pathIndex
  );

  // 将列车实体加入到场景中
  trainEntity = viewer.entities.add({
    // 设置可用时间范围，确保实体只在指定的时间段内可见
    availability: new Cesium.TimeIntervalCollection([
      new Cesium.TimeInterval({
        start: startTime,
        stop: endTime,
      }),
    ]),
    // 设置实体的实时位置，这里使用的是一个位置属性对象 `property`
    position: property,
    // 定义模型的方向为基于速度的方向属性
    orientation: new Cesium.VelocityOrientationProperty(property),
    // 模型设置，包括比例、模型文件路径和最小像素大小
    model: {
      scale: 0.17,
      uri: '/src/assets/model/metro.gltf',
      minimumPixelSize: 40,
    },
  });

  // clock是干嘛的?
  viewer.trackedEntity = trainEntity;
  viewer.clock.startTime = startTime.clone();
  viewer.clock.stopTime = endTime.clone();
  viewer.clock.currentTime = startTime.clone();
  // 监听时钟，如果列车到达站点，更新列车人数信息，并给一个暂停时间
  clockListener = viewer.clock.onTick.addEventListener(tickEventHandler);
};

// 处理漫游效果，使用TimeIntervalCollection
const handlePosition = (speed, pathIndex) => {
  const property = new Cesium.SampledProperty(Cesium.Cartesian3);
  // 这里的时间可以自己定义
  let startTime = Cesium.JulianDate.fromDate(new Date(2015, 1, 1, 8));
  // 通过速度计算最终时间, 从一号线第一个站点到最后一个站点所有点的经纬度坐标集合
  const restPath = currentLine.value.paths.slice(
    pathIndex,
    currentLine.value.paths.length - 1
  );
  // 经纬度转为Caterian3数组
  const positions = getPositions(restPath);
  // 根据速度计算总时间和每段时间, siteTimes是线路中相邻path所需的时间(数组), timeSum是从开始点到终点所用秒数
  const { siteTimes, timeSum } = getSiteTimes(positions, speed);
  // 计算到达终点的实际时间
  const endTime = Cesium.JulianDate.addSeconds(
    startTime,
    timeSum,
    new Cesium.JulianDate()
  );
  // 遍历坐标数组, 设置经过每一个坐标点的实际时间, 并添加到Sampled属性中
  positions.forEach((position, index) => {
    const time = Cesium.JulianDate.addSeconds(
      startTime,
      siteTimes[index],
      new Cesium.JulianDate()
    );
    property.addSample(time, position);
  });
  return {
    property,
    startTime,
    endTime,
  };
};

// 将经纬度坐标对象的数组转成世界坐标, 格式: [{lng: 140, lat: 30, 0}, {lng: 140, lat: 30, 0},...]
function getPositions(coordinates) {
  return coordinates.map(coordinate => {
    const cartesian = Cesium.Cartographic.toCartesian(
      Cesium.Cartographic.fromDegrees(coordinate.lng, coordinate.lat, 0)
    );
    return cartesian;
  });
}

// 当距离小于20米的时候，就可以给列车一个暂停
let apporachDistance = 20;
let popupController;
const tickEventHandler = () => {
  if (!trainEntity) return; // 确保 trainEntity 存在

  // 模型position属性中获取当前坐标的时间
  const startPosition = trainEntity.position.getValue(viewer.clock.currentTime);

  console.log('metroIndex.value为', metroIndex.value);
  //通过当前的metroIndex和速度计算下一个站点的坐标
  const { position } = stationData.value[metroIndex.value + 1];
  const endPosition = new Cesium.Cartesian3.fromDegrees(
    position.lng,
    position.lat
  );
  // 计算相邻两个站点之间的距离
  let distance = Cesium.Cartesian3.distance(startPosition, endPosition);
  // 距离小于给定值
  if (distance <= apporachDistance) {
    // 站点id变大，下一次计算的distance也会变大
    metroIndex.value++;
    // 将列车暂停
    viewer.clock.shouldAnimate = false;
    // 3s后恢复
    setTimeout(() => {
      viewer.clock.shouldAnimate = true;
    }, 2000);
  }
  // 还需要通过startPosition计算气泡框坐标
  popupController && popupController.changePosition(startPosition);
};

// 渲染气泡框
const renderBubble = trainInfo => {
  const { currentPassengers, lineName } = trainInfo;
  popupController = new SimpleLabel(viewer, {
    label: '',
    isShow: true,
    attr: {
      lineName: lineName,
      currentPassengers: currentPassengers,
    },
    type: 'carPopup',
    offset: [150, 200],
  });
  popupController.addLabel();
};
</script>

<style scoped lang="scss">
@import url('http://at.alicdn.com/t/c/font_4778950_jht8cywqcuq.css');

.center-wrapper {
  display: flex;
  justify-content: space-between;
  position: absolute;
  bottom: 90px;
  left: 29%;
  width: 800px;
  height: 280px;
  z-index: 1020;

  /* 地铁线路列表 */
  #subLine-controller {
    width: 180px;
    background-color: rgba(0, 0, 0, 0.3);
    border: 1px solid #ab7818;
    display: flex;
    flex-direction: column;
  }

  /* 站点列表 */
  #station-controller {
    width: 600px;
    border: 1px solid #ab7818;
    background-color: rgba(0, 0, 0, 0.3);
    color: #fff;
    display: flex;
    flex-direction: column;

    .item-wrapper {
      justify-content: flex-start;

      .item {
        position: relative;
        margin: 0 7px;

        &:hover::after {
          content: attr(data-fulltext); /* 显示完整文本 */
          position: absolute;
          color: #fff; /* 提示框文字颜色 */
          bottom: -80%; /* 提示框位于元素下方 */
          left: 0px;
          white-space: nowrap; /* 允许提示框内的文本换行 */
          z-index: 1030;
        }
      }
    }
  }

  .item-wrapper {
    display: flex;
    justify-content: space-around;
    align-content: space-around;
    flex-wrap: wrap;
    flex: 1;
    padding: 12px 4px;
    overflow: hidden;

    .item {
      width: 70px;
      height: 25px;
      display: flex;
      align-items: center;
      justify-content: space-evenly;
      background-color: rgba(255, 255, 255, 0.2);
      border: 1px solid #885f12;
      color: #fff;
      font-size: 0.8vw;
      pointer-events: all;

      &:hover {
        border: 1px solid #d8961a;
        cursor: default;
      }

      span {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        width: 42px;
      }

      .box {
        width: 10px;
        height: 10px;
        border-width: 1px;
        border-style: solid;
        background: transparent;
        user-select: all;
        cursor: pointer;
        transition: all 0.3s linear;
        z-index: 1040;
      }
    }
  }

  .title-bg {
    line-height: 30px;
    margin-left: 10px;
    background: rgb(255, 255, 255);
    background-image: linear-gradient(
      180deg,
      rgba(255, 255, 255, 1) 9%,
      rgba(211, 156, 50, 1) 57%
    );
    background-clip: text; //保证-webkit-background-clip不会提示错误
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
  }
}
</style>
